package com.flyme.module.base.provider;

import cn.hutool.http.HttpUtil;
import com.flyme.common.core.model.ResultBody;
import com.flyme.core.base.supper.entity.EntityMap;
import com.flyme.module.order.client.entity.Order;
import com.flyme.module.order.client.entity.PayAccount;
import lombok.extern.slf4j.Slf4j;
import org.jdom.Document;
import org.jdom.Element;
import org.jdom.input.SAXBuilder;

import javax.servlet.http.HttpServletRequest;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.math.BigDecimal;
import java.security.MessageDigest;
import java.text.SimpleDateFormat;
import java.util.*;
@Slf4j
public class CxPayUtil {
    public final static String PAY_UNIFIEDORDER = "https://api.mch.weixin.qq.com/pay/unifiedorder";
    /**
     * 小程序端支付
     * @param request
     * @param
     * @return
     */
    public  ResultBody cx_recharge(HttpServletRequest request, PayAccount payAccount, String openid, Order order) {
        SortedMap<String, Object> packageParams = new TreeMap<String, Object>();
        packageParams.put("appid", payAccount.getAppId());
        String nonce_str = getNonceStr();
        String spbill_create_ip = getIp(request);
        String trade_type = "JSAPI";
        if (spbill_create_ip.indexOf(",") > 0) {
            spbill_create_ip = spbill_create_ip.split(",")[0];
        }
        //订单类型（balance余额充值，order订单支付）
        packageParams.put("attach", "考试报名缴费");
        packageParams.put("body", "考试报名缴费");
        packageParams.put("mch_id",payAccount.getPartner());
        packageParams.put("nonce_str", nonce_str);
        packageParams.put("notify_url", payAccount.getNotifyUrl());
        packageParams.put("out_trade_no", order.getOutTradeNo());
        packageParams.put("spbill_create_ip", spbill_create_ip);
        if (payAccount.getIsTest()) {
            packageParams.put("total_fee", 1);
        } else {
            packageParams.put("total_fee", order.getOrderAmount().multiply(new BigDecimal(100)).intValue());
        }
        packageParams.put("trade_type", trade_type);
        packageParams.put("openid", openid);
        // 获取签名
        String sign = createSign(packageParams, payAccount.getPrivateKey());
        String xml = "<xml>" + "<appid>" + payAccount.getAppId() + "</appid>" + "<attach>" + packageParams.get("attach") + "</attach>"
            + "<body><![CDATA[考试报名缴费]]></body>" + "<mch_id>" + packageParams.get("mch_id") + "</mch_id>" +
            "<nonce_str>" + nonce_str + "</nonce_str>" + "<notify_url>" + packageParams.get("notify_url") + "</notify_url>"
            + "<openid>" + openid + "</openid>" + "<out_trade_no>" + packageParams.get("out_trade_no") + "</out_trade_no>" +
            "<spbill_create_ip>" + spbill_create_ip + "</spbill_create_ip>"
            + "<total_fee>" + packageParams.get("total_fee") + "</total_fee>"
            + "<trade_type>" + trade_type + "</trade_type>" + "<sign>" + sign + "</sign>" + "</xml>";
        log.error("xml======" + xml);
        EntityMap pi = new EntityMap();
        Boolean tag = getPayNo(pi, xml);
        if (tag) {
            // 获取到prepayid后对以下字段进行签名最终发送给app
            SortedMap<String, Object> finalpackage = new TreeMap<String, Object>();
            String timestamp = System.currentTimeMillis() + "";
            finalpackage.put("appId", payAccount.getAppId());
            finalpackage.put("timeStamp", timestamp);
            finalpackage.put("nonceStr", nonce_str);
            finalpackage.put("package", "prepay_id=" + pi.get("prepay_id"));
            finalpackage.put("signType", "MD5");
            String finalsign = createSign(finalpackage, payAccount.getPrivateKey());
            pi.put("timestamp", timestamp);
            pi.put("sign", finalsign);
            pi.put("nonce_str", nonce_str);
            pi.put("appid", payAccount.getAppId());
            return ResultBody.success(pi);
        } else {
            return ResultBody.failed(pi.get("msg"));
        }
    }

    /**
     * 获取子结点的xml
     *
     * @param children
     * @return String
     */
    public static String getChildrenText(List<?> children) {
        StringBuffer sb = new StringBuffer();
        if (!children.isEmpty()) {
            Iterator<?> it = children.iterator();
            while (it.hasNext()) {
                Element e = (Element) it.next();
                String name = e.getName();
                String value = e.getTextNormalize();
                List<?> list = e.getChildren();
                sb.append("<" + name + ">");
                if (!list.isEmpty()) {
                    sb.append(getChildrenText(list));
                }
                sb.append(value);
                sb.append("</" + name + ">");
            }
        }

        return sb.toString();
    }

    /***获取流*/
    public InputStream String2Inputstream(String str) {
        return new ByteArrayInputStream(str.getBytes());
    }


    /***创建签名*/
    public String createSign(SortedMap<String, Object> packageParams, String key) {
        StringBuffer sb = new StringBuffer();
        Set<?> es = packageParams.entrySet();
        Iterator<?> it = es.iterator();
        while (it.hasNext()) {
            Map.Entry entry = (Map.Entry) it.next();
            String k = (String) entry.getKey();
            Object v = entry.getValue();
            if (null != v && !"".equals(v) && !"sign".equals(k) && !"key".equals(k)) {
                sb.append(k + "=" + v + "&");
            }
        }
        sb.append("key=" + key);
        String sign = null;
        try {
            sign = md5(sb.toString(), "UTF-8").toUpperCase();
        } catch (Exception e) {
            e.printStackTrace();
            return "";
        }
        return sign;
    }

    /**
     * MD5加密
     *
     * @param data
     * @return
     * @throws Exception
     */
    public String md5(String data, String charset) throws Exception {
        MessageDigest md = MessageDigest.getInstance("MD5");
        byte[] array = md.digest(data.getBytes("UTF-8"));
        StringBuilder sb = new StringBuilder();
        for (byte item : array) {
            sb.append(Integer.toHexString((item & 0xFF) | 0x100).substring(1, 3));
        }
        return sb.toString().toUpperCase();
    }

    /**
     * 获取随机数
     *
     * @return String
     */
    public String getNonceStr() {
        String currTime = getCurrTime();
        // 8位日期
        String strTime = currTime.substring(8, currTime.length());
        // 四位随机数
        String strRandom = buildRandom(4) + "";
        // 10位序列号,可以自行调整。
        String strReq = strTime + strRandom;
        return strReq;
    }
    /**
     * 获取当前日期 yyyyMMddHHmmss
     *
     * @return String
     */
    public String getCurrTime() {
        Date now = new Date();
        SimpleDateFormat outFormat = new SimpleDateFormat("yyyyMMddHHmmss");
        String s = outFormat.format(now);
        return s;
    }

    /**
     * 取出一个指定长度大小的随机正整数.
     *
     * @param length int 设定所取出随机数的长度。length小于11
     * @return int 返回生成的随机数。
     */
    public int buildRandom(int length) {
        int num = 1;
        double random = Math.random();
        if (random < 0.1) {
            random = random + 0.1;
        }
        for (int i = 0; i < length; i++) {
            num = num * 10;
        }
        return (int) ((random * num));
    }

    /**
     * 获取IP地址
     *
     * @param request
     * @return
     */
    public String getIp(HttpServletRequest request) {
        String ip = request.getHeader("x-forwarded-for");
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("WL-Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("HTTP_CLIENT_IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("HTTP_X_FORWARDED_FOR");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getRemoteAddr();
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            return "39.108.52.121";
        }
        if (ip.contains(", ")) {
            //如果存在多个反向代理，获得的IP是一个用逗号分隔的IP集合，取第一个
            //X-Forwarded-For: client  第一个
            String[] ipaddrs = ip.split(",");
            //默认取第一个ip地址
            ip = ipaddrs[0];
        }
        return ip;
    }
    /****获取支付信息**/
    public Boolean getPayNo(EntityMap payParam, String xmlParam) {
        try {
            String jsonStr = HttpUtil.post(PAY_UNIFIEDORDER, xmlParam);
            Map<String, String> map = doXMLParse(jsonStr);
            if (jsonStr.indexOf("FAIL") != -1) {
                payParam.put("msg", map.get("return_msg"));
                return false;
            }
            payParam.put("prepay_id", map.get("prepay_id"));
            return true;
        } catch (Exception e) {
            return false;
        }
    }
    /**
     * 解析xml,返回第一级元素键值对。如果第一级元素有子节点，则此节点的值是子节点的xml数据。
     *
     * @param strxml
     * @return map
     */
    public Map<String, String> doXMLParse(String strxml) throws Exception {
        if (null == strxml || "".equals(strxml)) {
            return null;
        }
        Map<String, String> m = new HashMap<String, String>();
        InputStream in = String2Inputstream(strxml);
        SAXBuilder builder = new SAXBuilder();
        Document doc = builder.build(in);
        Element root = doc.getRootElement();
        List<?> list = root.getChildren();
        Iterator<?> it = list.iterator();
        while (it.hasNext()) {
            Element e = (Element) it.next();
            String k = e.getName();
            String v = "";
            List<?> children = e.getChildren();
            if (children.isEmpty()) {
                v = e.getTextNormalize();
            } else {
                v = getChildrenText(children);
            }
            m.put(k, v);
        }
        // 关闭流
        in.close();
        return m;
    }




}
